/*
MIT License

Copyright (c) 2024 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo
*/

#ifndef simodo_inout_fmt
#define simodo_inout_fmt

/*! \file fmt.h
    \brief Класс форматирования
*/

#include "simodo/inout/convert/functions.h"

#include <string>
#include <cstring>
#include <stdexcept>

namespace simodo::inout
{
    inline const char * FMT_PATTERN {"%1%2%3%4%5%6%7%8%9%0"};

    class fmt
    {
        std::string _str;
        size_t      _shift;

    public:
        fmt(const std::string & s, size_t shift=0)    : _str(s), _shift(shift)       {}
        fmt(const std::u16string & s, size_t shift=0) : _str(toU8(s)), _shift(shift) {}

        const std::string & str()   const { return _str; }
        size_t              shift() const { return _shift; }

        operator std::string () const { return _str; }

    public:
        template <typename T>
        auto arg(T a) -> typename std::enable_if<std::is_same_v<T, short unsigned>, fmt>::type
        { return arg(unsigned(a)); }
        template <typename T>
        auto arg(T a) -> typename std::enable_if<
            std::is_arithmetic_v<T> && !std::is_same_v<T, short unsigned>, fmt
        >::type
        { replace(std::to_string(a)); return fmt(_str, _shift+2); }
        template <typename T>
        auto arg(T a) -> typename std::enable_if<std::is_convertible_v<T, std::string>, fmt>::type
        { replace(a); return fmt(_str, _shift+2); }
        template <typename T>
        auto arg(T a) -> typename std::enable_if<std::is_convertible_v<T, std::u16string>, fmt>::type
        { replace(toU8(a)); return fmt(_str, _shift+2); }

    protected:
        void replace(const char * s, size_t size = std::string::npos);

        void replace(const std::string s) { replace(s.c_str(), s.size()); }
    };

}

#endif // simodo_inout_fmt
